using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace DVDVideoSoft.Controls
{
    /// <summary>
    /// The purpose of this class is to continue to provide the regular functionality of button class with
    /// some additional bitmap enhancments. These enhancements allow the specification of bitmaps for each
    /// state of the button. In addition, it makes use of the alignment properties already provided by the
    /// base button class. Since this class renders the image, it should appear similar accross platforms.
    /// Based on the http://www.codeproject.com/KB/buttons/XCtrls.aspx by JSimms
    /// </summary>
    public class ImageButton : //System.Windows.Forms.UserControl
        System.Windows.Forms.Button
    {
        #region Private Variables

        private Image _ImageNormal = null;
        private Image _ImageFocused = null;
        private Image _ImagePressed = null;
        private Image _ImageMouseOver = null;
        private Image _ImageInactive = null;
        private Color _BorderColor = Color.Transparent;
        private Color _InnerBorderColor = Color.Transparent;
        private Color _InnerBorderColor_Focus = Color.Transparent;
        private Color _InnerBorderColor_MouseOver = Color.Transparent;
        private Color _ImageBorderColor = Color.Transparent;
        private bool _StretchImage = true;
        private bool _TextDropShadow = false;
        private int _Padding = 5;
        private bool offsetPressedContent = true;
        private bool _ImageBorderEnabled = false;
        private bool _ImageDropShadow = false;
        private bool _FocusRectangleEnabled = true;
        private BtnState btnState = BtnState.Normal;
        private bool CapturingMouse = false;

        #endregion
        #region Public Properties
        [Browsable(false)]
        new public Image Image
        {
            get { return base.Image; }
            set { base.Image = value; }
        }
        [Browsable(false)]
        new public System.Windows.Forms.ImageList ImageList
        {
            get { return base.ImageList; }
            set { base.ImageList = value; }
        }
        [Browsable(false)]
        new public int ImageIndex
        {
            get { return base.ImageIndex; }
            set { base.ImageIndex = value; }
        }
        /// <summary>
        /// Enable the shadowing of the button text
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("enables the text to cast a shadow"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool TextDropShadow
        {
            get { return _TextDropShadow; }
            set { _TextDropShadow = value; }
        }
        /// <summary>
        /// Enables the dashed focus rectangle
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("enables the focus rectangle"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool FocusRectangleEnabled
        {
            get { return _FocusRectangleEnabled; }
            set { _FocusRectangleEnabled = value; }
        }

        /// <summary>
        /// Enable the shadowing of the image in the button
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("enables the image to cast a shadow"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool ImageDropShadow
        {
            get { return _ImageDropShadow; }
            set { _ImageDropShadow = value; }
        }
        /// <summary>
        /// This specifies the color of image border. Note, this is only valid if ImageBorder is enabled.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Color of the border around the image"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Color ImageBorderColor
        {
            get { return _ImageBorderColor; }
            set { _ImageBorderColor = value; }
        }
        /// <summary>
        /// This enables/disables the bordering of the image.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Enables the bordering of the image"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool ImageBorderEnabled
        {
            get { return _ImageBorderEnabled; }
            set { _ImageBorderEnabled = value; }
        }
        /// <summary>
        /// Color of the border around the button
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Color of the border around the button"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Color BorderColor
        {
            get { return _BorderColor; }
            set { _BorderColor = value; }
        }
        /// <summary>
        /// Color of the inner border when the button has focus
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Color of the inner border when the button has focus"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Color InnerBorderColor_Focus
        {
            get { return _InnerBorderColor_Focus; }
            set { _InnerBorderColor_Focus = value; }
        }
        /// <summary>
        /// Color of the inner border when the button does not have focus
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Color of the inner border when the button does not hvae focus"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Color InnerBorderColor
        {
            get { return _InnerBorderColor; }
            set { _InnerBorderColor = value; }
        }
        /// <summary>
        /// Color of the inner border when the mouse is over the button.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("color of the inner border when the mouse is over the button"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Color InnerBorderColor_MouseOver
        {
            get { return _InnerBorderColor_MouseOver; }
            set { _InnerBorderColor_MouseOver = value; }
        }
        /// <summary>
        /// Stretches the image across the button
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("stretch the impage to the size of the button"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool StretchImage
        {
            get { return _StretchImage; }
            set { _StretchImage = value; }
        }
        /// <summary>
        /// Specifies the padding in units of pixels around the button button elements. Currently,
        /// the button elements consist of the image and text.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("padded pixels around the image and text"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public new int Padding
        {
            get { return _Padding; }
            set { _Padding = value; }
        }
        /// <summary>
        /// Set to true if to offset button elements when button is pressed
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Set to true if to offset image/text when button is pressed"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public bool OffsetPressedContent
        {
            get
            {
                return
                    offsetPressedContent;
            }
            set { offsetPressedContent = value; }
        }
        /// <summary>
        /// Image to be displayed while the button state is in normal state. If the other
        /// states do not specify an image, this image is used as a substitute.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Image to be displayed while the button state is in normal state"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Image ImageNormal
        {
            get { return _ImageNormal; }
            set { _ImageNormal = value; }
        }
        /// <summary>
        /// Specifies an image to use while the button has focus.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Image to be displayed while the button has focus"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Image ImageFocused
        {
            get { return _ImageFocused; }
            set { _ImageFocused = value; }
        }
        /// <summary>
        /// Specifies an image to use while the button is enactive.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Image to be displayed while the button is inactive"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Image ImageInactive
        {
            get { return _ImageInactive; }
            set { _ImageInactive = value; }
        }
        /// <summary>
        /// Specifies an image to use while the button is pressed.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Image to be displayed while the button state is pressed"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Image ImagePressed
        {
            get { return _ImagePressed; }
            set { _ImagePressed = value; }
        }
        /// <summary>
        /// Specifies an image to use while the mouse is over the button.
        /// </summary>
        [Browsable(true),
         CategoryAttribute("Appearance"),
         Description("Image to be displayed while the button state is MouseOver"),
         System.ComponentModel.RefreshProperties(RefreshProperties.Repaint)
        ]
        public Image ImageMouseOver
        {
            get { return _ImageMouseOver; }
            set { _ImageMouseOver = value; }
        }
        #endregion
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
        /// <summary>
        /// The ImageButton constructor
        /// </summary>
        public ImageButton()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.DoubleBuffer, true);
            this.SetStyle(ControlStyles.ResizeRedraw, true);
            this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.BackColor = Color.Transparent;

            InitializeComponent();
            // TODO: Add any initialization after the InitComponent call

            //LoadGraphics();
        }
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                    components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
        }
        #endregion


        #region Paint Methods
        /// <summary>
        /// This method paints the button in its entirety.
        /// </summary>
        /// <param name="e">paint arguments use to paint the button</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

            //CreateRegion(0);
            
            //paint_Background(e);
            //paint_Text_orig(e);
            //paint_Image(e);
            //paint_Text(e);
            //paint_Border(e);
            //paint_InnerBorder(e);
            //paint_FocusBorder(e);
        }
        /// <summary>
        /// This method fills the background of the button.
        /// </summary>
        /// <param name="e">paint arguments use to paint the button</param>
        private void paint_Background(PaintEventArgs e)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;

            Graphics g = e.Graphics;
            Rectangle rect = new Rectangle(0, 0, Size.Width, Size.Height);
            //
            // get color of background
            //
            Color color = this.BackColor;
            if (btnState == BtnState.Inactive)
                color = Color.LightGray;
            //
            // intialize ColorArray and Positions Array
            //
            Color[] ColorArray = null;
            float[] PositionArray = null;
            //
            // initialize color array for a button that is pushed
            //
            if (btnState == BtnState.Pushed)
            {
                ColorArray = new Color[] {
                Blend(this.BackColor, Color.White, 80),
                Blend(this.BackColor, Color.White, 40),
                Blend(this.BackColor, Color.Black, 0),
                Blend(this.BackColor, Color.Black, 0),
                Blend(this.BackColor, Color.White, 40),
                Blend(this.BackColor, Color.White, 80),
            };
                PositionArray = new float[] { 0.0f, .05f, .40f, .60f, .95f, 1.0f };
            }
            //
            // else, initialize color array for a button that is normal or disabled
            //
            else
            {
                ColorArray = new Color[] {
                Blend(color, Color.White, 80),
                Blend(color, Color.White, 90),
                Blend(color, Color.White, 30),
                Blend(color, Color.White, 00),
                Blend(color, Color.Black, 30),
                Blend(color, Color.Black, 20),
            };
                PositionArray = new float[] { 0.0f, .15f, .40f, .65f, .80f, 1.0f };
            }
            //
            // create blend variable for the interpolate the colors
            //
            System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
            blend.Colors = ColorArray;
            blend.Positions = PositionArray;
            //
            // create vertical gradient brush
            //
            System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, this.BackColor, Blend(this.BackColor, this.BackColor, 10), System.Drawing.Drawing2D.LinearGradientMode.Vertical);
            brush.InterpolationColors = blend;

            g.FillRectangle(brush, rect);
            //g.FillRectangle(false ? brush : Brushes.Silver, rect);
            //
            // release resources
            //
            brush.Dispose();
        }
        /// <summary>
        /// paints the 1 pixel border around the button. The color of
        /// the border is defined by BorderColor
        /// </summary>
        /// <param name="e">paint arguments use to paint the button</param>
        private void paint_Border(PaintEventArgs e)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;
            //
            // create the pen
            //
            Pen pen = new Pen(this.BorderColor, 1);
            //
            // get the points for the border
            //
            Point[] pts = border_Get(0, 0, this.Width - 1, this.Height - 1);
            //
            // paint the border
            //
            e.Graphics.DrawLines(pen, pts);
            //
            // release resources
            //
            pen.Dispose();
        }
        /// <summary>
        /// paints the focus rectangle.
        /// </summary>
        /// <param name="e">paint arguments use to paint the button</param>
        private void paint_FocusBorder(PaintEventArgs e)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;
            //
            // if the button has focus, and focus rectangle is enabled,
            // draw the focus box
            //
            if (this.Focused)
            {
                if (FocusRectangleEnabled)
                {
                    ControlPaint.DrawFocusRectangle(e.Graphics, new Rectangle(3, 3, this.Width - 6, this.Height - 6), Color.Black, this.BackColor);
                }
            }
        }
        /// <summary>
        /// paint the inner border of the button.
        /// </summary>
        /// <param name="e">paint arguments use to paint the button</param>
        private void paint_InnerBorder(PaintEventArgs e)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;

            Graphics g = e.Graphics;
            Rectangle rect = new Rectangle(0, 0, Size.Width, Size.Height);

            Color color = this.BackColor;
            //
            // get color of inner border
            //
            switch (btnState)
            {
                case BtnState.Inactive:
                    color = Color.Gray;
                    break;

                case BtnState.Normal:
                    if (this.Focused)
                        color = this.InnerBorderColor_Focus;
                    else
                        color = this.InnerBorderColor;
                    break;

                case BtnState.Pushed:
                    color = Blend(InnerBorderColor_Focus, Color.Black, 10);
                    break;

                case BtnState.MouseOver:
                    color = InnerBorderColor_MouseOver;
                    break;
            }
            //
            // populate color and position arrays
            //
            Color[] ColorArray = null;
            float[] PositionArray = null;
            if (btnState == BtnState.Pushed)
            {
                ColorArray = new Color[] {
                Blend(color, Color.Black, 20),
                Blend(color, Color.Black, 10),
                Blend(color, Color.White, 00),
                Blend(color, Color.White, 50),
                Blend(color, Color.White, 85),
                Blend(color, Color.White, 90),
            };
                PositionArray = new float[] { 0.0f, .20f, .50f, .60f, .90f, 1.0f };
            }
            else
            {
                ColorArray = new Color[] {
                Blend(color, Color.White, 80),
                Blend(color, Color.White, 60),
                Blend(color, Color.White, 10),
                Blend(color, Color.White, 00),
                Blend(color, Color.Black, 20),
                Blend(color, Color.Black, 50),
            };
                PositionArray = new float[] { 0.0f, .20f, .50f, .60f, .90f, 1.0f };
            }
            //
            // create blend object
            //
            System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
            blend.Colors = ColorArray;
            blend.Positions = PositionArray;
            //
            // create gradient brush and pen
            //
            System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, this.BackColor, Blend(this.BackColor, this.BackColor, 10), System.Drawing.Drawing2D.LinearGradientMode.Vertical);
            brush.InterpolationColors = blend;
            Pen pen0 = new Pen(brush, 1);
            //
            // get points array to draw the line
            //
            Point[] pts = border_Get(0, 0, this.Width - 1, this.Height - 1);
            //
            // draw line 0
            //
            this.border_Contract(1, ref pts);
            e.Graphics.DrawLines(pen0, pts);
            //
            // draw line 1
            //
            this.border_Contract(1, ref pts);
            e.Graphics.DrawLines(pen0, pts);
            //
            // release resources
            //
            pen0.Dispose();
            brush.Dispose();
        }

        public override ContentAlignment TextAlign { get; set; }
        public new TextImageRelation TextImageRelation { get; set; }

        /// <summary>
        /// This method paints the text and text shadow for the button.
        /// </summary>
        /// <param name="e">paint arguments use to paint the button</param>
        private void paint_Text(PaintEventArgs e)
        {
            //Point pt2 = new Point(3, 3);
            //e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), pt2.X, pt2.Y);
            //return;
            if (e == null)
                return;
            if (e.Graphics == null)
                return;
            Rectangle rect = GetTextDestinationRect2();
            //
            // do offset if button is pushed
            //
            if ((btnState == BtnState.Pushed) && OffsetPressedContent)
                rect.Offset(1, 1);
            //
            // caculate bounding rectagle for the text
            //
            SizeF size = txt_Size(e.Graphics, this.Text, this.Font);
            //
            // calculate the starting location to paint the text
            //
            //Point pt = new Point(5, 2);//Calculate_LeftEdgeTopEdge(this.TextAlign, rect, (int) size.Width, (int) size.Height);
            Point pt = CalculateTextLeftTopCorner(this.TextAlign, rect, (int)size.Width, (int)size.Height);
            //
            // If button state is inactive, paint the inactive text
            //
            if (btnState == BtnState.Inactive)
            {
                e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(Color.White), pt.X + 1, pt.Y + 1);
                e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(Color.FromArgb(50, 50, 50)), pt.X, pt.Y);
            }
            //
            // else, paint the text and text shadow
            //
            else
            {
                //
                // paint text shadow
                //
                //if (TextDropShadow)
                //{
                //    Brush TransparentBrush0 = new SolidBrush(Color.FromArgb(50, Color.Black));
                //    Brush TransparentBrush1 = new SolidBrush(Color.FromArgb(20, Color.Black));

                //    e.Graphics.DrawString(this.Text, this.Font, TransparentBrush0, pt.X, pt.Y + 1);
                //    e.Graphics.DrawString(this.Text, this.Font, TransparentBrush0, pt.X + 1, pt.Y);

                //    e.Graphics.DrawString(this.Text, this.Font, TransparentBrush1, pt.X + 1, pt.Y + 1);
                //    e.Graphics.DrawString(this.Text, this.Font, TransparentBrush1, pt.X, pt.Y + 2);
                //    e.Graphics.DrawString(this.Text, this.Font, TransparentBrush1, pt.X + 2, pt.Y);

                //    TransparentBrush0.Dispose();
                //    TransparentBrush1.Dispose();
                //}
                //
                // paint text
                //
                e.Graphics.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), pt.X, pt.Y);
            }
        }

        private Point CalculateTextLeftTopCorner(ContentAlignment Alignment, Rectangle rect, int nWidth, int nHeight)
        {
            Point textLocation = rect.Location;

            //textLocation.Offset(6, 2);    //CalculateTextLeftTopCorner(this.TextAlign, rect, (int)size.Width, (int)size.Height);
            //if (btnState == BtnState.Pushed && OffsetPressedContent)
            //    rect.Location.Offset(1, 1);//CalculateTextLeftTopCorner(this.TextAlign, rect, (int)size.Width, (int)size.Height);

            return textLocation;
        }
        ///// <summary>
        ///// This method paints the text and text shadow for the button.
        ///// </summary>
        ///// <param name="e">paint arguments use to paint the button</param>
        //private void paint_Text_orig(PaintEventArgs e)
        //{
        //    if(e == null)
        //        return;
        //    if(e.Graphics == null)
        //        return;
        //    Rectangle rect = GetTextDestinationRect();
        //    //
        //    // do offset if button is pushed
        //    //
        //    if( (btnState == BtnState.Pushed) && (OffsetPressedContent) )
        //           rect.Offset(1,1);
        //    //
        //    // caculate bounding rectagle for the text
        //    //
        //    SizeF size = txt_Size(e.Graphics,this.Text,this.Font);
        //    //
        //    // calculate the starting location to paint the text
        //    //
        //    Point pt = Calculate_LeftEdgeTopEdge(this.TextAlign, rect, (int) size.Width, (int) size.Height);
        //    //
        //    // If button state is inactive, paint the inactive text
        //    //
        //    if(btnState == BtnState.Inactive)
        //    {
        //        e.Graphics.DrawString(this.Text,this.Font, new SolidBrush(Color.White),pt.X+1,pt.Y+1);
        //        e.Graphics.DrawString(this.Text,this.Font, new SolidBrush(Color.FromArgb(50,50,50)),pt.X,pt.Y);
        //    }
        //    //
        //    // else, paint the text and text shadow
        //    //
        //    else
        //    {
        //        //
        //        // paint text shadow
        //        //
        //        if(TextDropShadow)
        //        {
        //            Brush TransparentBrush0 = new SolidBrush( Color.FromArgb(50, Color.Black  ) ) ;
        //            Brush TransparentBrush1 = new SolidBrush( Color.FromArgb(20, Color.Black  ) ) ;

        //            e.Graphics.DrawString(this.Text,this.Font, TransparentBrush0,pt.X,pt.Y+1);
        //            e.Graphics.DrawString(this.Text,this.Font, TransparentBrush0,pt.X+1,pt.Y);

        //            e.Graphics.DrawString(this.Text,this.Font, TransparentBrush1,pt.X+1,pt.Y+1);
        //            e.Graphics.DrawString(this.Text,this.Font, TransparentBrush1,pt.X,pt.Y+2);
        //            e.Graphics.DrawString(this.Text,this.Font, TransparentBrush1,pt.X+2,pt.Y);

        //            TransparentBrush0.Dispose();
        //            TransparentBrush1.Dispose();
        //        }
        //        //
        //        // paint text
        //        //
        //        e.Graphics.DrawString(this.Text,this.Font, new SolidBrush(this.ForeColor),pt.X,pt.Y);
        //    }
        //}
        /// <summary>
        /// Paints a border around the image. If Image drop shadow is enabled,
        /// a shodow is drawn too.
        /// </summary>
        /// <param name="g">The graphics object</param>
        /// <param name="ImageRect">the rectangle region of the image</param>
        private void paint_ImageBorder(Graphics g, Rectangle ImageRect)
        {
            Rectangle rect = ImageRect;

            //
            // If ImageDropShadow = true, draw shadow
            //
            if (ImageDropShadow)
            {
                Pen p0 = new Pen(Color.FromArgb(80, 0, 0, 0));
                Pen p1 = new Pen(Color.FromArgb(40, 0, 0, 0));
                g.DrawLine(p0, new Point(rect.Right, rect.Bottom), new Point(rect.Right + 1, rect.Bottom));
                g.DrawLine(p0, new Point(rect.Right + 1, rect.Top + 1), new Point(rect.Right + 1, rect.Bottom + 0));
                g.DrawLine(p1, new Point(rect.Right + 2, rect.Top + 2), new Point(rect.Right + 2, rect.Bottom + 1));
                g.DrawLine(p0, new Point(rect.Left + 1, rect.Bottom + 1), new Point(rect.Right + 0, rect.Bottom + 1));
                g.DrawLine(p1, new Point(rect.Left + 1, rect.Bottom + 2), new Point(rect.Right + 1, rect.Bottom + 2));
            }
            //
            // Draw Image Border
            //
            if (ImageBorderEnabled)
            {
                Color[] ColorArray = null;
                float[] PositionArray = null;
                Color color = this.ImageBorderColor;
                if (!this.Enabled)
                    color = Color.LightGray;
                //
                // initialize color and position array
                //
                ColorArray = new Color[] {
                Blend(color, Color.White, 40),
                Blend(color, Color.White, 20),
                Blend(color, Color.White, 30),
                Blend(color, Color.White, 00),
                Blend(color, Color.Black, 30),
                Blend(color, Color.Black, 70),
            };
                PositionArray = new float[] { 0.0f, .20f, .50f, .60f, .90f, 1.0f };
                //
                // create blend object
                //
                System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
                blend.Colors = ColorArray;
                blend.Positions = PositionArray;
                //
                // create brush and pens
                //
                System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(rect, this.BackColor, Blend(this.BackColor, this.BackColor, 10), System.Drawing.Drawing2D.LinearGradientMode.Vertical);
                brush.InterpolationColors = blend;
                Pen pen0 = new Pen(brush, 1);
                Pen pen1 = new Pen(Color.Black);
                //
                // calculate points to draw line
                //
                rect.Inflate(1, 1);
                Point[] pts = border_Get(rect.Left, rect.Top, rect.Width, rect.Height);
                this.border_Contract(1, ref pts);
                //
                // draw line 0
                //
                g.DrawLines(pen1, pts);
                //
                // draw line 1
                //
                this.border_Contract(1, ref pts);
                g.DrawLines(pen0, pts);
                //
                // release resources
                //
                pen1.Dispose();
                pen0.Dispose();
                brush.Dispose();
            }
        }
        /// <summary>
        /// Paints the image on the button.
        /// </summary>
        /// <param name="e"></param>

        private void paint_Image(PaintEventArgs e)
        {
            if (e == null)
                return;
            if (e.Graphics == null)
                return;
            Image image = GetCurrentImage(btnState);

            if (image != null)
            {
                Graphics g = e.Graphics;
                Rectangle rect = GetImageDestinationRect();

                //if ((btnState == BtnState.Pushed) && (offsetPressedContent))
                //    rect.Offset(1, 1);
                if (this.StretchImage)
                {
                    g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
                }
                else
                {
                    Rectangle r = GetImageDestinationRect();
                    //g.DrawImage(image,rect.Left,rect.Top);
                    g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
                }
                //paint_ImageBorder(g, rect);
            }
            //e.Graphics.DrawString("Channel", this.Font, Brushes.Black, new PointF(4, 3));
        }
        #endregion
        #region Helper Methods
        /// <summary>
        /// Calculates the required size to draw a text string
        /// </summary>
        /// <param name="g">the graphics object</param>
        /// <param name="strText">string to calculate text region</param>
        /// <param name="font">font to use for the string</param>
        /// <returns>returns the size required to draw a text string</returns>
        private SizeF txt_Size(Graphics g, string strText, Font font)
        {
            SizeF size = g.MeasureString(strText, font);

            return (size);
        }

        public int TextHOffset { get; set; }

        private Rectangle GetTextDestinationRect2()
        {

            SizeF size = txt_Size(this.CreateGraphics(), this.Text, this.Font);
            Rectangle rect;

            int textHOffset = this.TextHOffset;
            if (this.TextImageRelation == System.Windows.Forms.TextImageRelation.ImageBeforeText)
            {
                Rectangle imageRect = GetImageDestinationRect();
                rect = new Rectangle(imageRect.Right, (this.Height - (int)size.Height) / 2, this.Width, this.Height);
            }
            else
                rect = new Rectangle(this.TextHOffset, (this.Height - (int)size.Height) / 2, this.ClientRectangle.Width - this.TextHOffset, this.Height);

            //this.Left, this.Top, this.Width, this.Height);
            //switch(this.ImageAlign)
            //{
            //    case ContentAlignment.BottomCenter:
            //        rect = new Rectangle(0,0,this.Width,ImageRect.Top);
            //        break;
            //    case ContentAlignment.BottomLeft:
            //        rect = new Rectangle(0,0,this.Width,ImageRect.Top);
            //        break;
            //    case ContentAlignment.BottomRight:
            //        rect = new Rectangle(0,0,this.Width,ImageRect.Top);
            //        break;
            //    case ContentAlignment.MiddleCenter:
            //        rect = new Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
            //        break;
            //    case ContentAlignment.MiddleLeft:
            //        rect = new Rectangle(ImageRect.Right,0,this.Width-ImageRect.Right,this.Height);
            //        break;
            //    case ContentAlignment.MiddleRight:
            //        rect = new Rectangle(0,0,ImageRect.Left,this.Height);
            //        break;
            //    case ContentAlignment.TopCenter:
            //        rect = new Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
            //        break;
            //    case ContentAlignment.TopLeft:
            //        rect = new Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
            //        break;
            //    case ContentAlignment.TopRight:
            //        rect = new Rectangle(0,ImageRect.Bottom,this.Width,this.Height-ImageRect.Bottom);
            //        break;
            //}
            //rect.Inflate(-this.Padding,-this.Padding);
            return rect;
        }
        /// <summary>
        /// Calculates the rectangular region used for text display.
        /// </summary>
        /// <returns>returns the rectangular region for the text display</returns>
        private Rectangle GetTextDestinationRect()
        {
            Rectangle ImageRect = GetImageDestinationRect();
            Rectangle rect = new Rectangle(0, 0, 0, 0);

            switch (this.ImageAlign)
            {
                case ContentAlignment.BottomCenter:
                    rect = new Rectangle(0, 0, this.Width, ImageRect.Top);
                    break;

                case ContentAlignment.BottomLeft:
                    rect = new Rectangle(0, 0, this.Width, ImageRect.Top);
                    break;

                case ContentAlignment.BottomRight:
                    rect = new Rectangle(0, 0, this.Width, ImageRect.Top);
                    break;

                case ContentAlignment.MiddleCenter:
                    rect = new Rectangle(0, ImageRect.Bottom, this.Width, this.Height - ImageRect.Bottom);
                    break;

                case ContentAlignment.MiddleLeft:
                    rect = new Rectangle(ImageRect.Right, 0, this.Width - ImageRect.Right, this.Height);
                    break;

                case ContentAlignment.MiddleRight:
                    rect = new Rectangle(0, 0, ImageRect.Left, this.Height);
                    break;

                case ContentAlignment.TopCenter:
                    rect = new Rectangle(0, ImageRect.Bottom, this.Width, this.Height - ImageRect.Bottom);
                    break;

                case ContentAlignment.TopLeft:
                    rect = new Rectangle(0, ImageRect.Bottom, this.Width, this.Height - ImageRect.Bottom);
                    break;

                case ContentAlignment.TopRight:
                    rect = new Rectangle(0, ImageRect.Bottom, this.Width, this.Height - ImageRect.Bottom);
                    break;
            }
            rect.Inflate(-this.Padding, -this.Padding);
            return (rect);
        }
        /// <summary>
        /// Calculates the rectangular region used for image display.
        /// </summary>
        /// <returns>returns the rectangular region used to display the image</returns>
        private Rectangle GetImageDestinationRect()
        {
            Rectangle rect = new Rectangle(0, 0, 0, 0);
            Image image = GetCurrentImage(this.btnState);

            if (image != null)
            {
                if (this.StretchImage)
                {
                    rect.Width = this.Width;
                    rect.Height = this.Height;
                }
                else
                {
                    rect.Width = image.Width;
                    rect.Height = image.Height;
                    Rectangle drect = new Rectangle(0, 0, this.Width, this.Height);
                    //drect.Inflate(-this.Padding,-this.Padding);
                    Point pt = Calculate_LeftEdgeTopEdge(this.ImageAlign, drect, image.Width, image.Height);
                    rect.Offset(pt);
                }
            }
            return (rect);
        }
        /// <summary>
        /// This method is used to retrieve the image used by the button for the given state.
        /// </summary>
        /// <param name="btnState">holds the state of the button</param>
        /// <returns>returns the button Image</returns>
        private Image GetCurrentImage(BtnState btnState)
        {
            Image image = ImageNormal;

            switch (btnState)
            {
                case BtnState.Normal:
                    if (this.Focused)
                    {
                        if (this.ImageFocused != null)
                            image = this.ImageFocused;
                    }
                    break;

                case BtnState.MouseOver:
                    if (ImageMouseOver != null)
                        image = ImageMouseOver;
                    break;

                case BtnState.Pushed:
                    if (ImagePressed != null)
                        image = ImagePressed;
                    break;

                case BtnState.Inactive:
                    if (ImageInactive != null)
                        image = ImageInactive;
                    else
                    {
                        if (image != null)
                        {
                            ImageInactive = ConvertToGrayscale(new Bitmap(ImageNormal));
                        }
                        image = ImageNormal;
                    }
                    break;
            }
            return (image);
        }
        /// <summary>
        /// converts a bitmap image to grayscale
        /// </summary>
        /// <param name="source">bitmap source</param>
        /// <returns>returns a grayscaled bitmap</returns>
        public Bitmap ConvertToGrayscale(Bitmap source)
        {
            Bitmap bm = new Bitmap(source.Width, source.Height);

            for (int y = 0; y < bm.Height; y++)
            {
                for (int x = 0; x < bm.Width; x++)
                {
                    Color c = source.GetPixel(x, y);
                    int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
                    bm.SetPixel(x, y, Color.FromArgb(luma, luma, luma));
                }
            }
            return bm;
        }
        /// <summary>
        /// calculates the left/top edge for content.
        /// </summary>
        /// <param name="Alignment">the alignment of the content</param>
        /// <param name="rect">rectagular region to place content</param>
        /// <param name="nWidth">with of content</param>
        /// <param name="nHeight">height of content</param>
        /// <returns>returns the left/top edge to place content</returns>
        private Point Calculate_LeftEdgeTopEdge(ContentAlignment Alignment, Rectangle rect, int nWidth, int nHeight)
        {
            Point pt = new Point(0, 0);

            switch (Alignment)
            {
                case ContentAlignment.BottomCenter:
                    pt.X = (rect.Width - nWidth) / 2;
                    pt.Y = rect.Height - nHeight;
                    break;

                case ContentAlignment.BottomLeft:
                    pt.X = 0;
                    pt.Y = rect.Height - nHeight;
                    break;

                case ContentAlignment.BottomRight:
                    pt.X = rect.Width - nWidth;
                    pt.Y = rect.Height - nHeight;
                    break;

                case ContentAlignment.MiddleCenter:
                    pt.X = (rect.Width - nWidth) / 2;
                    pt.Y = (rect.Height - nHeight) / 2;
                    break;

                case ContentAlignment.MiddleLeft:
                    pt.X = 0;
                    pt.Y = (rect.Height - nHeight) / 2;
                    break;

                case ContentAlignment.MiddleRight:
                    pt.X = rect.Width - nWidth;
                    pt.Y = (rect.Height - nHeight) / 2;
                    break;

                case ContentAlignment.TopCenter:
                    pt.X = (rect.Width - nWidth) / 2;
                    pt.Y = 0;
                    break;

                case ContentAlignment.TopLeft:
                    pt.X = 0;
                    pt.Y = 0;
                    break;

                case ContentAlignment.TopRight:
                    pt.X = rect.Width - nWidth;
                    pt.Y = 0;
                    break;
            }
            pt.X += rect.Left;
            pt.Y += rect.Top;
            return (pt);
        }
        /// <summary>
        /// creates the region for the control. The region will have curved edges.
        /// This prevents any drawing outside of the region.
        /// </summary>
        private void CreateRegion(int nContract)
        {
            Point[] points = border_Get(0, 0, this.Width, this.Height);
            border_Contract(nContract, ref points);
            System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
            path.AddLines(points);
            this.Region = new Region(path);
        }
        /// <summary>
        /// contract the array of points that define the border.
        /// </summary>
        /// <param name="nPixel">number of pixels to conract</param>
        /// <param name="pts">array of points that define the border</param>
        private void border_Contract(int nPixel, ref Point[] pts)
        {
            int a = nPixel;

            pts[0].X += a; pts[0].Y += a;
            pts[1].X -= a; pts[1].Y += a;
            pts[2].X -= a; pts[2].Y += a;
            pts[3].X -= a; pts[3].Y += a;
            pts[4].X -= a; pts[4].Y -= a;
            pts[5].X -= a; pts[5].Y -= a;
            pts[6].X -= a; pts[6].Y -= a;
            pts[7].X += a; pts[7].Y -= a;
            pts[8].X += a; pts[8].Y -= a;
            pts[9].X += a; pts[9].Y -= a;
            pts[10].X += a; pts[10].Y += a;
            pts[11].X += a; pts[10].Y += a;
        }
        /// <summary>
        /// calculates the array of points that make up a border
        /// </summary>
        /// <param name="nLeftEdge">left edge of border</param>
        /// <param name="nTopEdge">top edge of border</param>
        /// <param name="nWidth">width of border</param>
        /// <param name="nHeight">height of border</param>
        /// <returns>returns an array of points that make up the border</returns>
        private Point[] border_Get(int nLeftEdge, int nTopEdge, int nWidth, int nHeight)
        {
            int X = nWidth;
            int Y = nHeight;

            Point[] points =
        {
            new Point(1, 0),
            new Point(X - 1, 0),
            new Point(X - 1, 1),
            new Point(X, 1),
            new Point(X, Y - 1),
            new Point(X - 1, Y - 1),
            new Point(X - 1, Y),
            new Point(1, Y),
            new Point(1, Y - 1),
            new Point(0, Y - 1),
            new Point(0, 1),
            new Point(1, 1)
        };
            for (int i = 0; i < points.Length; i++)
            {
                points[i].Offset(nLeftEdge, nTopEdge);
            }
            return points;
        }
        /// <summary>
        /// Increments or decrements the red/green/blue values of a color. It enforces that the
        /// values do not go out of the bounds of 0..255
        /// </summary>
        /// <param name="SColor">source color</param>
        /// <param name="RED">red shift</param>
        /// <param name="GREEN">green shift</param>
        /// <param name="BLUE">blue shift</param>
        /// <returns>returns the calculated color</returns>
        private static Color Shade(Color SColor, int RED, int GREEN, int BLUE)
        {
            int r = SColor.R;
            int g = SColor.G;
            int b = SColor.B;

            r += RED;
            if (r > 0xFF)
                r = 0xFF;
            if (r < 0)
                r = 0;

            g += GREEN;
            if (g > 0xFF)
                g = 0xFF;
            if (g < 0)
                g = 0;

            b += BLUE;
            if (b > 0xFF)
                b = 0xFF;
            if (b < 0)
                b = 0;

            return Color.FromArgb(r, g, b);
        }
        /// <summary>
        /// Calculates a blended color using the specified parameters.
        /// </summary>
        /// <param name="SColor">Source Color (color moving from)</param>
        /// <param name="DColor">Dest Color (color movving towards)</param>
        /// <param name="Percentage">Percentage of Dest Color (0..100)</param>
        /// <returns></returns>
        private static Color Blend(Color SColor, Color DColor, int Percentage)
        {
            int r = SColor.R + ((DColor.R - SColor.R) * Percentage) / 100;
            int g = SColor.G + ((DColor.G - SColor.G) * Percentage) / 100;
            int b = SColor.B + ((DColor.B - SColor.B) * Percentage) / 100;

            return Color.FromArgb(r, g, b);
        }
        #endregion
        #region Events Methods
        /// <summary>
        /// Mouse Down Event:
        /// set BtnState to Pushed and Capturing mouse to true
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.Capture = true;
            this.CapturingMouse = true;
            btnState = BtnState.Pushed;
            this.Invalidate();
        }
        /// <summary>
        /// Mouse Up Event:
        /// Set BtnState to Normal and set CapturingMouse to false
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            btnState = BtnState.Normal;
            this.Invalidate();
            this.CapturingMouse = false;
            this.Capture = false;
            this.Invalidate();
        }
        /// <summary>
        /// Mouse Leave Event:
        /// Set BtnState to normal if we CapturingMouse = true
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            if (!CapturingMouse)
            {
                btnState = BtnState.Normal;
                this.Invalidate();
            }
        }
        /// <summary>
        /// Mouse Move Event:
        /// If CapturingMouse = true and mouse coordinates are within button region,
        /// set BtnState to Pushed, otherwise set BtnState to Normal.
        /// If CapturingMouse = false, then set BtnState to MouseOver
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (CapturingMouse)
            {
                Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
                btnState = BtnState.Normal;
                if ((e.X >= rect.Left) && (e.X <= rect.Right))
                {
                    if ((e.Y >= rect.Top) && (e.Y <= rect.Bottom))
                    {
                        btnState = BtnState.Pushed;
                    }
                }
                this.Capture = true;
                this.Invalidate();
            }
            else
            {
                //if(!this.Focused)
                {
                    if (btnState != BtnState.MouseOver)
                    {
                        btnState = BtnState.MouseOver;
                        this.Invalidate();
                    }
                }
            }
        }
        /// <summary>
        /// Enable/Disable Event:
        /// If button became enabled, set BtnState to Normal
        /// else set BtnState to Inactive
        /// </summary>
        /// <param name="e"></param>
        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
            if (this.Enabled)
            {
                this.btnState = BtnState.Normal;
            }
            else
            {
                this.btnState = BtnState.Inactive;
            }
            this.Invalidate();
        }
        /// <summary>
        /// Lose Focus Event:
        /// set btnState to Normal
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);
            if (this.Enabled)
            {
                this.btnState = BtnState.Normal;
            }
            this.Invalidate();
        }


        #endregion
    }
}
